package com.zte.claa.inficombo.csa.app.service.csa.impl;

import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.zte.claa.inficombo.csa.app.comm.csif.CSIFCommService;
import com.zte.claa.inficombo.csa.app.comm.csif.CSIFReportData;
import com.zte.claa.inficombo.csa.app.comm.csif.CSIFReportDataListener;
import com.zte.claa.inficombo.csa.app.config.CSAConfigProps;
import com.zte.claa.inficombo.csa.app.service.rptparse.IParser;
import com.zte.claa.inficombo.csa.app.service.rptparse.ParserContainer;

public class DataReportManager implements CSIFReportDataListener {
	// 终端数据上报消息的cmd
	public static final String UPDATA_CMD = "updata";
	// logger日志.
	private Logger logger = LoggerFactory.getLogger(DataReportManager.class);
	
	// AppEUI-->CSIFCommService应用，创建时设置.
	private Map<String, CSIFCommService> appeui2CSIFMap = null;
	
	// 上报数据解析器.
	private ParserContainer rptParserContainer;

	// 一个appeui对应一个updata收发线程池，一个非业务数据上报（如dev_join, forced_quit)线程池，确保业务数据处理有序、迅速；
    private ExecutorService extraRptExecSvr;
    // updata收发线程池
    private ExecutorService dataRptExecSvr;
    
    // csa配置参数》
    private CSAConfigProps configProps;
	
    /**
     * 构建器.
     * 
     * @param configProps
     */
    public DataReportManager(CSAConfigProps configProps, Map<String, CSIFCommService> appeui2CSIFMap){
    	this.configProps = configProps;
    	this.appeui2CSIFMap = appeui2CSIFMap;    	
    	this.init();
    }
    
    /**
     * 初始化方法。
     * 注： ThreadPoolExecutor 线程池的 queue有多重模式，其中：LinkedBlockingQueue是无界队列，此时maxcorepoolsize参数无效。
     */
    private void init(){
    	// this.dataRptExecSvr = Executors.newFixedThreadPool(this.configProps.getRptdatawokernum());
    	// this.extraRptExecSvr = Executors.newFixedThreadPool(this.configProps.getExtdatawokernum());
    	int rptWorkerNum = this.configProps.getRptdatawokernum();
    	this.dataRptExecSvr = new ThreadPoolExecutor(rptWorkerNum, rptWorkerNum+5, 120, TimeUnit.MILLISECONDS, 
    			new LinkedBlockingQueue<Runnable>(this.configProps.getRptdataqueuesize()));
    	int extWorkerNum = this.configProps.getExtdatawokernum();
    	this.extraRptExecSvr = new ThreadPoolExecutor(extWorkerNum, extWorkerNum+3, 120, TimeUnit.MILLISECONDS, 
    			new LinkedBlockingQueue<Runnable>(this.configProps.getExtdataqueuesize()));
    }
    
    /**
     * 
     * @param rptParserContainer
     */
    public void setParserContainer(ParserContainer rptParserContainer){
    	this.rptParserContainer = rptParserContainer;
    }
    
    /**
	 * 下电
	 */
	public void shutdown(){
		this.appeui2CSIFMap = null;
		if(this.extraRptExecSvr != null){
			this.extraRptExecSvr.shutdown();
			this.extraRptExecSvr = null;
		}
		if(this.dataRptExecSvr != null){
			this.dataRptExecSvr.shutdown();
			this.dataRptExecSvr = null;
		}
	}
	
	/**
	 * 数据上报总入口。
	 */
	@Override
	public void onReport(String appEUI, CSIFReportData rptData) {
		if(rptData == null){
			return;
		}
		logger.debug("Receive updata: "+rptData);
		String cmd = rptData.getCmd();
		if(UPDATA_CMD.equalsIgnoreCase(cmd.trim())){
			this.addUpdataToPool(appEUI, rptData);
		} else {
			this.addExtradataToPool(appEUI, rptData);
		}		
	}
	
	/**
	 * 将updata消息添加到线程池中》
	 * 
	 * @param jsonData
	 */
	private void addUpdataToPool(String appEUI, CSIFReportData data){
		this.dataRptExecSvr.submit(new Runnable(){
			@Override
			public void run() {
				processUpdata(appEUI, data);
			}
		});
	}
	
	/**
	 * 将其他上报消息添加到线程池
	 * 
	 * @param data
	 */
	private void addExtradataToPool(String appEUI, CSIFReportData data){
		this.extraRptExecSvr.submit(new Runnable(){
			@Override
			public void run() {
				processExtradata(appEUI, data);
			}
		});
	}
	
	/**
	 * 处理终端上报数据。
	 * 
	 * @param jsonData
	 */
	private void processUpdata(String appEui, CSIFReportData data) {
		IParser parser = this.rptParserContainer.getParser(UPDATA_CMD);
		try {
			parser.parseData(data.getJsonData(), this.appeui2CSIFMap.get(appEui));
		} catch (Exception e) {
			logger.error("processUpdata failed: " + data + ", err=" + e.getMessage(), e);
		} 
	}
	
	/**
	 * 处理其他上报消息。
	 * 
	 * @param data
	 */
	private void processExtradata(String appEui, CSIFReportData data){
		IParser parser = this.rptParserContainer.getParser(data.getCmd());
		try {
			parser.parseData(data.getJsonData(), this.appeui2CSIFMap.get(appEui));
		} catch (Exception e) {
			logger.error("processUpdata failed: " + data + ", err=" + e.getMessage());
		}
	}

}
